

#include "xapp_config.h"

#if USER_CHECK_ENABLED( NOTIFICATION )

#include <string.h> 
#include <stdbool.h>

#include "xapp_event_send.h"
#include "xapp_notification.h"
#include "xapp_profile.h"
#include "xapp_osllv.h"

#include "em_ble.h"

#include "lib_ancs.h"
#include "convert.h"
#include "log.h"

#if USER_CHECK_LOG_ENABLED( NOTIFICATION )
#include "log.h"
#define LOG     LOG_INFO 
#define LOG0    LOG_INFO0 
#define LOG1    LOG_INFO1
#define LOG2    LOG_INFO2
#define LOG3    LOG_INFO3
#else 
#define LOG(...) 
#define LOG0(...)
#define LOG1(...)
#define LOG2(...)
#define LOG3(...)
#endif 

// #define XAPP_NOTIF_ARRAY_SIZE           (8)
// #define XAPP_NOTIF_ARRAY_SIZE_MASK      (XAPP_NOTIF_ARRAY_SIZE - 1)

const uint8_t appIconIdx[] = {0,1,2,3,4,5,6,7,8,9,10,11,1,12, 13, 13};


static uint16_t                     ancs_local_data[NOTIFICATION_NUMS_OF_MSG][NOTIFICATION_CHARS_MAX_NUM];  // 4K RAM  
static uint32_t                     m_local_idx = 0;

static xapp_notif_calling_t         m_app_calling; 
static uint8_t                      m_local_app_type; 
// static bool                         m_notif_is_enabled = true; 
// static bool                         m_notif_is_receiving = false; 

static xapp_notif_type_t            msg_list[NOTIFICATION_NUMS_OF_MSG];

static list_node_t*                 mp_list_head = NULL; 
// static uint8_t                      m_idx_display = 0;

static xapp_notif_desc_t            m_app_notif_desc; 

/////////////////////////////////////////////////////////////////////////////////////////////////////
#if 1 // list node 
static inline int msg_list_get_buff_not_used(void)
{
    int i;
    for( i = 0; i < NOTIFICATION_NUMS_OF_MSG; i++)
    {
        if( msg_list[i].used == 0 )
        {
            return i;
        }
    }
    
    for( i = 0; i < NOTIFICATION_NUMS_OF_MSG; i++)
    {
        msg_list[i].used = 0;
    }
    
    return 0; 
}

static inline void msg_list_all_sort(void)
{
    list_node_t* tmp = mp_list_head;
    int no = 0;
    while( tmp != NULL ) 
    {
        ((xapp_notif_type_t*)tmp)->idx = no;
        ++no;
        tmp = tmp->p_next;
    }
}
static inline void msg_list_sort(list_node_t* p_node, int no)
{
    while( p_node != NULL ) 
    {
        ((xapp_notif_type_t*)p_node)->idx = no;
        ++no;
        p_node = p_node->p_next;
    }
}

static void msg_list_remove(int index)
{
    list_node_t* p_node = list_node_get_at( &mp_list_head, index );
    if( p_node != NULL ) 
    {
        ((xapp_notif_type_t*)p_node)->used = 0;
        list_node_remove( &mp_list_head, p_node );
        msg_list_all_sort();
    }
}

static xapp_notif_type_t* msg_malloc_node(void)
{
    int size = 0; 
    if( mp_list_head != NULL ) 
    {
        size = list_node_size_get( mp_list_head );
    }
    
    int index;
    list_node_t* p_new_node;
    
    if( size == 0 ) 
    {
        index = msg_list_get_buff_not_used();
        msg_list[index].idx = 0;
        msg_list[index].used = 1;
        msg_list[index].node.p_next = NULL;
        
        p_new_node = &msg_list[index].node;
    }
    else if( size >= NOTIFICATION_NUMS_OF_MSG )
    {
        list_node_t* p_last_node = list_node_get_last( &mp_list_head );
        xapp_notif_type_t* msg = (xapp_notif_type_t*)p_last_node;
        msg->used = 0;
        
        list_node_remove( &mp_list_head, p_last_node );

        msg_list_sort( mp_list_head, 1 ); 
        
        msg->used = 1;
        p_new_node = &msg->node;
    }
    else 
    {
        index = msg_list_get_buff_not_used();
        msg_list[index].idx = 0;
        msg_list[index].used = 1;
        msg_list[index].node.p_next = NULL;
        
        msg_list_sort( mp_list_head, 1 ); 
        
        p_new_node = &msg_list[index].node;
    }
    
    if( mp_list_head == NULL ) 
    {
        mp_list_head = p_new_node;
        p_new_node->p_next = NULL;
    }
    else 
    {
        p_new_node->p_next = mp_list_head;
        mp_list_head = p_new_node;
    }
    
    return (xapp_notif_type_t*)p_new_node;
}

#endif // !list node 

void xapp_notif_init(void) 
{
    memset( &m_app_calling, 0, sizeof( m_app_calling ) ); 
    memset( &m_app_notif_desc, 0, sizeof(m_app_notif_desc ) );

    mp_list_head = NULL; 
    m_app_notif_desc.enabled = true; 
    m_app_notif_desc.has_messages = false;
    m_app_notif_desc.p_calling = &m_app_calling;
} 

const xapp_notif_desc_t* xapp_notif_get_desc(void)
{
    return &m_app_notif_desc; 
}

void xapp_notif_set_enabled(bool enabled)
{
    m_app_notif_desc.enabled = enabled;
}

void xapp_notif_reset(void)
{
    memset( msg_list, 0, sizeof( msg_list ) ); 
    mp_list_head = NULL; 
    m_local_idx = 0;
    m_app_notif_desc.has_messages = false; 
}


static void xapp_notif_calling_receive_from_ancs(int calltype ) 
{
    m_app_calling.from_iOS = true; 
    m_app_calling.type = calltype;    
    // const lib_ancs_attr_title_t *ptitle = (const lib_ancs_attr_title_t*) lib_ancs_get_title(); 
    const lib_ancs_data_t *ptitle = &lib_ancs_data_get()->title;

    if( ptitle->len > 0)
    {
        m_app_calling.len = conv_encoding_utf8_to_unicode( ptitle->pdata, ptitle->len, m_app_calling.title, XAPP_NOTIF_CALLING_TITLE_SIZE);
    }
    else
    {
        m_app_calling.len = 0; 
    }
    // set new user ui 
    if( m_app_notif_desc.enabled )
    {
        if( calltype == XAPP_NOTIF_CALL_INCOMING_FROM_IOS )
        {
            OSLLV_SEND_TAG_EXE( OSLLV_TAG_INCOMING_CALL );
        }
        else 
        {
            OSLLV_SEND_TAG_EXE( OSLLV_TAG_MISSED_CALL );
        }
    }
}

void xapp_notif_calling_received(int calltype, uint8_t *utf8, uint16_t len)
{
    m_app_calling.from_iOS = false; 
    m_app_calling.type = calltype;    
    m_app_calling.len = conv_encoding_utf8_to_unicode( utf8, len, m_app_calling.title, XAPP_NOTIF_CALLING_TITLE_SIZE);

    // set new user ui 
    if( m_app_notif_desc.enabled )
    {
        if( calltype != XAPP_NOTIF_CALL_MISSED_CALL )
        {
            OSLLV_SEND_TAG_EXE( OSLLV_TAG_INCOMING_CALL );
        }
        else 
        {
            OSLLV_SEND_TAG_EXE( OSLLV_TAG_MISSED_CALL );
        }
    }
}


//extern void ancs_handleIncomingCall(uint8_t accept);
void xapp_notif_calling_action(uint8_t accept)
{
    if( m_app_calling.from_iOS > 0)
    {
       em_ble_ancs_action_handle( accept ); 
    }
    else
    {
        // handle for others HOST 
    }
}

/// type - what type of message required to save 
/// utf8 - utf8-code received
/// len  - utf8-code size 
/// *note: require to covert utf8 to unicode 
static void xapp_notif_ancs_receive_new_notification(uint32_t type )//, uint32_t * p_data, int count)
{    
    xapp_notif_type_t *p_msg = msg_malloc_node();// &m_xapp_notif.msg_array[idx];
    if( p_msg == NULL )
    {
        return;
    }
    // 记录信息数量
    m_app_notif_desc.has_messages = true; 
    m_app_notif_desc.count_of_msg = list_node_size_get( mp_list_head );
        
    if( p_msg->text.pdata != NULL )
    {
        p_msg->text.pdata = NULL; 
    }
    // const lib_ancs_attr_title_t* p_ancs_title = lib_ancs_get_title();
    // const lib_ancs_attr_msg_t*   p_ancs_msg = lib_ancs_get_message(); 
    // const lib_ancs_attr_date_t*  p_ancs_datetime = lib_ancs_get_date(); 
    const lib_ancs_data_list_t* p_ancs_data_list = lib_ancs_data_get();
    const lib_ancs_data_t* p_ancs_title = &p_ancs_data_list->title;
    const lib_ancs_data_t* p_ancs_message = &p_ancs_data_list->message;
    const lib_ancs_data_t* p_ancs_datetime = &p_ancs_data_list->datetime;
    
    p_msg->text.len_of_title = conv_utf8_to_unicode_cnt( p_ancs_title->pdata, p_ancs_title->len ) ;
    p_msg->text.len_of_msg =  conv_utf8_to_unicode_cnt( p_ancs_message->pdata, p_ancs_message->len ); 
    LOG_INFO2("[UNICODE]: title = %d, msg = %d", p_msg->text.len_of_title, p_msg->text.len_of_msg); 
    
    p_msg->text.pdata = ancs_local_data[ m_local_idx % NOTIFICATION_NUMS_OF_MSG ]; 
    m_local_idx ++;
    
    if( type < sizeof(appIconIdx) / sizeof(appIconIdx[0]) )
    {
        p_msg->type = appIconIdx[type];
    }
    else 
    {
        p_msg->type = LIB_ANCS_APP_TYPE_INVALID;
    }
    if( p_ancs_title->len > 0 ) //no icon defined, get title  
    {
        if( p_ancs_title != NULL && p_ancs_title->len > 0)
        {
            p_msg->text.len_of_title = conv_encoding_utf8_to_unicode( 
                p_ancs_title->pdata, 
                p_ancs_title->len, 
                p_msg->text.pdata, 
                XAPP_NOTIF_TEXT_LEN);
        }
        if( p_msg->text.len_of_title > 0)
        {
            p_msg->text.pdata[p_msg->text.len_of_title ++] = ':'; 
        }
    }

    if( p_ancs_message->len > 0){
        p_msg->text.len_of_msg = conv_encoding_utf8_to_unicode(
            p_ancs_message->pdata, 
            p_ancs_message->len, 
            p_msg->text.pdata + p_msg->text.len_of_title, 
            XAPP_NOTIF_TEXT_LEN - p_msg->text.len_of_title);        
    }

    if( p_ancs_datetime->len == XAPP_NOTIF_DATETIME_FIXED_LEN )
    {
        conv_ancs_datetime( (uint8_t*)p_ancs_datetime->pdata, p_ancs_datetime->len, 
        & p_msg->datetime.year, &p_msg->datetime.month, &p_msg->datetime.day, &p_msg->datetime.hour, &p_msg->datetime.minute, &p_msg->datetime.second ) ;      
    }

    if( m_app_notif_desc.enabled )
    {
        OSLLV_SEND_TAG_EXE( OSLLV_TAG_NEW_MESSAGE );
    }
}



void xapp_notif_receive_notification_from_ancs( int category_id )
{
    const profile_notification_t* p_notif = xapp_profile_get_notification();    
    if( (p_notif->category & ( 1 << category_id )) == 0 )
    {
        return; 
    }
    
    switch( (lib_ancs_category_id_t)category_id)
    {
        // call only care title 
        case LIB_ANCS_CATEGORY_ID_IncomingCall: 
        {
            xapp_notif_calling_receive_from_ancs( XAPP_NOTIF_CALL_INCOMING_FROM_IOS );// , (iqw_ancs_attr_t*)p_ancs_attr_data[IQW_ANCS_ATTR_ID_TITLE] );
        }
        break;
        case LIB_ANCS_CATEGORY_ID_MissCall:
        {
            xapp_notif_calling_receive_from_ancs( XAPP_NOTIF_CALL_MISSED_CALL );// , (iqw_ancs_attr_t*)p_ancs_attr_data[IQW_ANCS_ATTR_ID_TITLE] );
        }
        break; 

        // find title
        default: 
        {// message 
            // const lib_ancs_attr_app_id_t* p_app_id = lib_ancs_get_appid();
            const lib_ancs_data_t* p_ancs_id = &lib_ancs_data_get()->appid;
            
            int ret = lib_ancs_find_bundle_id( p_ancs_id );
            if( ret < LIB_ANCS_APP_TYPE_COUNT)
            { // check allow to display 
                if( (p_notif->application & ( 1 << ret )) == 0 )
                {
                    break; 
                }
            }

            xapp_notif_ancs_receive_new_notification( ret );
        }
        break; 
    }
}

void xapp_notif_receive_remove_calling(void)
{
    //xapp_view_set( XAPP_VIEW_REMOVE_CALL );
    USER_EVENT_SEND_TYPE( CUSTOM_EVT_TYPE_CALLING_REMOVED );
}

void xapp_notif_priv_app_set(uint8_t type)
{
    m_local_app_type = type; 
    lib_ancs_reset(); 
}

void xapp_notif_priv_set_completed(void)
{
    xapp_notif_ancs_receive_new_notification( m_local_app_type ); 
}

const xapp_notif_type_t * xapp_notif_get_msg(void)
{
    list_node_t* p_node = list_node_get_at( &mp_list_head, m_app_notif_desc.idx );
    return (xapp_notif_type_t*)p_node;
} 

const xapp_notif_type_t* xapp_notif_get_msg_by_index(uint8_t index)
{
    list_node_t const * p_node = list_node_get_at( &mp_list_head, index );
    return (xapp_notif_type_t*)p_node;
}

inline void xapp_notif_resume_display_index(void)
{
    m_app_notif_desc.idx = 0;
}

void xapp_notif_delete_current_msg(void)
{
    msg_list_remove( m_app_notif_desc.idx );

    // int count = list_node_size_get( mp_list_head );
    m_app_notif_desc.count_of_msg = list_node_size_get( mp_list_head );
    if( m_app_notif_desc.count_of_msg > 0)
    {
        m_app_notif_desc.idx = m_app_notif_desc.count_of_msg - 1;
    }
    else 
    {
        m_app_notif_desc.idx = 0;
    }
}

void xapp_notif_delete_msg_by_index( uint8_t idx)
{
    msg_list_remove( idx );
    m_app_notif_desc.count_of_msg = list_node_size_get( mp_list_head );
    if( m_app_notif_desc.count_of_msg > 0 )
    {
        m_app_notif_desc.idx = m_app_notif_desc.count_of_msg - 1; 
    }
    else 
    {
        m_app_notif_desc.idx = 0;
    }
}

int xapp_notif_set_last_msg(void)
{
//    int count = list_node_size_get( mp_list_head );
    if( m_app_notif_desc.count_of_msg > 1 ) 
    {
        if( m_app_notif_desc.idx == 0 ) 
        {
            m_app_notif_desc.idx = m_app_notif_desc.count_of_msg - 1;
        }
        else 
        {
            m_app_notif_desc.idx --;
        }
        return 0; 
    }
    return 1; 
}
int xapp_notif_set_next_msg(void)
{
//    int count = list_node_size_get( mp_list_head );
    if( m_app_notif_desc.count_of_msg > 1 ) 
    {
        if( m_app_notif_desc.idx < (m_app_notif_desc.count_of_msg - 1) ) 
        {
            m_app_notif_desc.idx ++;
        }
        else 
        {
            m_app_notif_desc.idx = 0; 
        }
        return 0; 
    }
    return 1; 
}


#endif // !USER_CHECK_ENABLED( NOTIFICATION )

